home *** CD-ROM | disk | FTP | other *** search
/ Network Support Library / RoseWare - Network Support Library.iso / apidev / ndr4.exe / VLM.TXT < prev   
Text File  |  1994-01-18  |  23KB  |  763 lines

  1. /****************************************************************************
  2. The following code was taken from the Network Developer's Resource, published
  3. by RoseWare.  All contents are Copyright (c) 1993, RoseWare.  All Rights
  4. Reserved.
  5.  
  6. This material is made available as a service for subscribers of the Network
  7. Developer's Resource.  This material is not public domain.  Simply put, if you
  8. are not a subscriber of the Network Developer's Resource, you are using this
  9. material illegally.  
  10.  
  11. Those interested in subscribing should contact RoseWare via:
  12.  
  13. CompuServe:    76711,110
  14. Internet:      76711.110@compuserve.com
  15. Phone:         (704) 258-9166
  16. Fax:           (704) 258-9374
  17. BBS:           (704) 258-8675
  18. US Mail:       P.O. Box 8564
  19.                Asheville, NC  28814-8564    
  20.  
  21. Also see the file SUBSCRIB.TXT in this ZIP file...
  22. ****************************************************************************/
  23.            ==> Calling the VLM shell from Borland Pascal <==
  24.  
  25. Well, the VLM shells are out and you're wondering, "How do I program for
  26. them? How do I make my code VLM smart?" As of the time that I am writing
  27. this article, Novell has released very little information as to how to
  28. interface into the VLM APIs. What little has been released has only gone
  29. out to a few people and the information is very incomplete and not very
  30. accurate.
  31.  
  32. But, with what information I do have and what I've managed to put
  33. together of other prominate NetWare nerds, I've managed to get quite a
  34. few things working. The code presented here is the basic interface into
  35. the VLM shell and lets you at least talk to it from Pascal. Once you get
  36. that far you can then start digging around for whatever API information
  37. you can come up with.
  38.  
  39. And, when you finally get the API information and you start making the
  40. new calls, you find that many of them either don't work, or barely work.
  41. So you have to be careful to program around the bugs and try to
  42. compensate by building smarts around a dumb API. I am currently using
  43. VLM 1.1 and it still, in my opinion, isn't ready yet. But, it is close
  44. enough to see the light at the end of the tunnel. Some day VLM shells
  45. are going to work and be great. So it's worth starting to move in that
  46. direction.
  47.  
  48. In my opinion, Novell has really failed the third party developers on
  49. these VLM shells. API information should have been available BEFORE
  50. these shells were ever released. So here it is almost a year AFTER and
  51. the information is rare, inaccurate, and incomplete. Novell has made no
  52. commitments as to when this situation will be fixed. I therefore
  53. encourage to to complain bitterly to Novell and encourage them to fix
  54. the problem, for their sake, as well as ours.
  55.  
  56.  
  57. THE VLM INTERFACE
  58. -----------------
  59.  
  60. The NETX shell was called by using Int 21 calls. The VLM shell is
  61. different. The first thing you do is an Int 2F call to get the address
  62. if the VLM API interface. Once you have that address, you use it to talk
  63. to the VLM. If this call fails then you're running under NETX and should
  64. then make the NETX call.
  65.  
  66. To call the VLM you push the VLM functions on the stack and call the VLM
  67. address. The assembler listing here is code I modified from the
  68. Turbopower Software Object Professional Library. If you're programming
  69. in Pascal, this is a "must have" library. It has everything in it and
  70. then some. If you don't have it already, get it.
  71.  
  72. With the NETX shells you created Request and Reply buffers with the
  73. first two bytes being the buffer length. You then passed registers
  74. pointing to these buffers. The VLM shells are different. Here the
  75. registers point to a "fragment list" which is a list of pointers and
  76. buffers lengths to send and receive data. Why you would want to do this,
  77. I don't know. But that's the way it is.
  78.  
  79. What I did in my interface was to create a structure that is like the
  80. old call, and translate it to the new call. I use a single fragment in
  81. my fragment list. I still pass the Request and Reply buffers with the
  82. first two bytes being the buffer length. But if I make a VLM call, I
  83. read the length word into the fragment list and move the buffer pointer
  84. forward to bytes to point to the data.
  85.  
  86. Most Netware calls use either $E1, $E2 or $E3 in the AH register. These
  87. calls are directly translated into VLM calls $15, $16 and $17. By
  88. looking at my examples, you can create VLM smart calls for most of your
  89. existing functions and will allow you to make your code somewhat VLM
  90. smart while we are still waiting for Novell to release "the good stuff".
  91.  
  92.  
  93. ASSEMBLER CODE
  94. --------------
  95.  
  96.  
  97.  
  98. ;******************************************************
  99. ;                   OPVLM.ASM 1.21
  100. ;               Vlm Interface routines
  101. ;     Copyright (c) TurboPower Software 1987, 1992.
  102. ; Portions Copyright (c) Sunny Hill Software 1985, 1986
  103. ;     and used under license to TurboPower Software
  104. ;                All rights reserved.
  105. ; Portions Copyright (c) Marc Perkel / Computer Tyme 1993
  106. ;
  107. ; Computer Tyme * 417-866-1222
  108. ; TurboPower Software * 719-260-6641
  109. ;
  110. ;******************************************************
  111.  
  112. ;****************************************************** Equates
  113.  
  114. ;Fields in an IntRegisters variable
  115.  
  116.         BpR     =       0
  117.         EsR     =       2
  118.         DsR     =       4
  119.         DiR     =       6
  120.         SiR     =       8
  121.         DxR     =       10
  122.         CxR     =       12
  123.         BxR     =       14
  124.         AxR     =       16
  125.         Flags   =       22
  126.  
  127. ;****************************************************** Data
  128.  
  129. DATA    SEGMENT BYTE PUBLIC
  130.  
  131. DATA    ENDS
  132.  
  133. ;****************************************************** Code
  134.  
  135. CODE    SEGMENT BYTE PUBLIC
  136.  
  137.         ASSUME  CS:CODE, DS:DATA
  138.  
  139.         PUBLIC  CallVlm
  140.  
  141. ;****************************************************** Structures
  142.  
  143. ;Structure of a pointer
  144.  
  145. Pointer STRUC
  146.         Ofst    DW      0
  147.         Segm    DW      0
  148. Pointer ENDS
  149.  
  150. ;****************************************************** EmulateInt
  151.  
  152. ;procedure CallVlm(var Regs : IntRegisters; IntAddr : Pointer;
  153. ;                      DestID, DestFun : Word);
  154.  
  155. ;Emulates an interrupt by filling the CPU registers with the values in Regs,
  156. ;clearing interrupts, pushing the flags, and calling far to IntAddr.
  157.  
  158. ;Equates for parameters
  159.  
  160. destFun EQU     word  ptr [BP+6]
  161. destID  EQU     word  ptr [BP+8]
  162. IntAddr EQU     DWORD PTR [BP+10]
  163. Regs    EQU     DWORD PTR [BP+14]
  164. Regs2   EQU     DWORD PTR [BP+20]       ;Regs after the 'interrupt' - pushed
  165.                                         ;BP, DS, and flags figure into
  166.                                         ;equation the second time around
  167.  
  168. ;Temporary variable stored in the code segment
  169.  
  170.         IntAddress      Pointer <>
  171.  
  172. CallVlm         PROC FAR
  173.  
  174.         PUSH    BP                              ;Save BP
  175.         MOV     BP,SP                           ;Set up stack frame
  176.         PUSHF                                   ;Save flags
  177.         PUSH    DS                              ;Save DS
  178.  
  179.         ;Load registers with contents of Regs
  180.  
  181.         PUSH    0                               ;VLM stack parameters
  182.         PUSH    DestID
  183.         PUSH    DestFun
  184.  
  185.         LDS     DI,Regs                         ;DS:DI points to Regs
  186.         MOV     AH,[DI].Flags                   ;Get new flags into AH
  187.         SAHF                                    ;Load flags from AH
  188.         MOV     BX,[DI].BxR                     ;Load BX
  189.         MOV     CX,[DI].CxR                     ;Load CX
  190.         MOV     DX,[DI].DxR                     ;Load DX
  191.  
  192.         ;Set up for the far call with interrupts off -- this section of code
  193.         ;is not re-entrant
  194.  
  195.         LES     SI,IntAddr                      ;ES:SI points to IntAddr
  196.         CLI                                     ;Interrupts off
  197.         PUSH    DS
  198.         PUSHF
  199.         MOV     AX,SEG DATA
  200.         MOV     DS,AX
  201.         MOV     AX,CS
  202.         MOV     DS,AX
  203.         MOV     DS:IntAddress.Ofst,SI           ;Save offset of IntAddr
  204.         MOV     DS:IntAddress.Segm,ES           ;Save segment
  205.         POPF
  206.         POP     DS
  207.         MOV     AX,[DI].AxR                     ;Load AX
  208.         MOV     BP,[DI].BpR                     ;Load BP
  209.         MOV     SI,[DI].SiR                     ;Load SI
  210.         MOV     ES,[DI].EsR                     ;Load ES
  211.         PUSH    [DI].DsR                        ;PUSH new DS
  212.         MOV     DI,[DI].DiR                     ;Load DI
  213.         POP     DS                              ;POP new DS
  214.  
  215.         ;Emulate interrupt
  216.  
  217.         CALL    DWORD PTR CS:IntAddress         ;Call IntAddr
  218.  
  219.         ;Get ready to load Regs
  220.  
  221.         PUSH    BP                              ;Save BP
  222.         MOV     BP,SP                           ;Set up stack frame
  223.         PUSHF                                   ;Save Flags
  224.         PUSH    ES                              ;Save ES
  225.         PUSH    DI                              ;Save DI
  226.  
  227.         ;Load Regs with new values
  228.  
  229.         LES     DI,Regs2                        ;ES:DI points to Regs
  230.         ADD     DI,AxR                          ;ES:DI points to Regs.AX
  231.         STD                                     ;Go backward
  232.         STOSW                                   ;Store AX
  233.         MOV     AX,BX                           ;Get BX into AX and store it
  234.         STOSW
  235.         MOV     AX,CX                           ;Get CX into AX and store it
  236.         STOSW
  237.         MOV     AX,DX                           ;Get DX into AX and store it
  238.         STOSW
  239.         MOV     AX,SI                           ;Get SI into AX and store it
  240.         STOSW
  241.         POP     AX                              ;POP saved DI into AX
  242.         STOSW
  243.         MOV     AX,DS                           ;Get DS into AX and store it
  244.         STOSW
  245.         POP     AX                              ;POP saved ES into AX
  246.         STOSW
  247.                                                 ;ES:DI now points to Regs.BP
  248.         POP     AX                              ;POP saved Flags into AX
  249.         POP     ES:[DI]                         ;POP saved BP into place
  250.         MOV     ES:[DI].Flags,AL                ;Store low byte of flags
  251.         CLD                                     ;Clear direction flag
  252.  
  253.         ;Clean up and return
  254.  
  255.         POP     DS                              ;Restore DS
  256.         POPF                                    ;Restore flags
  257.         POP     BP                              ;Restore BP
  258.         RET     12
  259.  
  260. CallVlm         ENDP
  261.  
  262. CODE    ENDS
  263.  
  264.         END
  265.  
  266.  
  267. PASCAL INTERFACE CODE
  268. ---------------------
  269.  
  270. This code compiles a Turbo Pascal Unit that you include with your
  271. program. By using the TransportCallEx procedures you should be able to
  272. make your programs somewhat VLM smart.
  273.  
  274.  
  275. {Novell VLM Shell Interface Routines
  276.  
  277. ;******************************************************
  278. ;                     VLM.PAS
  279. ;               Vlm Interface routines
  280. ;     Copyright (c) TurboPower Software 1987, 1992.
  281. ; Portions Copyright (c) Sunny Hill Software 1985, 1986
  282. ;     and used under license to TurboPower Software
  283. ;                All rights reserved.
  284. ; Portions Copyright (c) Marc Perkel / Computer Tyme 1993
  285. ;
  286. ; Computer Tyme * 417-866-1222
  287. ; TurboPower Software * 719-260-6641
  288. ;
  289. ;******************************************************}
  290.  
  291. {$F+}
  292.  
  293. Unit VLM;
  294.  
  295. Interface
  296.  
  297. type
  298.   Dummy5 = array[1..5] of Word;
  299.   IntRegisters =
  300.     record
  301.       case Byte of
  302.         1 : (BP, ES, DS, DI, SI, DX, CX, BX, AX, IP, CS, Flags : Word);
  303.         2 : (Dummy : Dummy5; DL, DH, CL, CH, BL, BH, AL, AH : Byte);
  304.     end;
  305.  
  306.   Str80 = String[80];
  307.   WordPtr = ^Word;
  308.  
  309.   OS =
  310.     record
  311.       O, S : Word;
  312.     end;
  313.  
  314. var
  315.   NovResult : Byte;
  316.   VlmAddr : Pointer;
  317.  
  318. {Procedures Exported}
  319.  
  320. Procedure VlmCall (var Regs : IntRegisters; DestID, DestFunc : Word);
  321. Procedure TransportCallE1 (Request, Reply : Pointer);
  322. Procedure TransportCallE2 (Request, Reply : Pointer);
  323. Procedure TransportCallE3 (Request, Reply : Pointer);
  324. Function ConTableSize : Byte;
  325. Function ConsoleOperator : Boolean;
  326. Function LoginName (Conn : Word) : String;
  327. Function NovConnection : Word;
  328. Function NovBinderyAccess : Byte;
  329. Function NumberOfPrinters : Byte;
  330. Function ObjectID (ObjName : Str80; T : Word) : LongInt;
  331. Function ObjectName (I : LongInt) : String;
  332. Function VlmLoaded : Boolean;
  333.  
  334.  
  335. Implementation
  336.  
  337. Uses
  338.   Dos;
  339.  
  340. {When this unit is initialized the variable VlmAddr is set to point to
  341.  the VLM shell call address if the VLM shell is found. If it isn't found,
  342.  the address is set ti nil.}
  343.  
  344.  
  345. Function VlmLoaded : Boolean;
  346. begin
  347.    VlmLoaded := VlmAddr <> nil;
  348. end;
  349.  
  350.  
  351. {This routine interfaces with VLMCALL.OBJ which pushes parameters
  352.  on the stack and calls the VLM Address}
  353.  
  354.  
  355. {$L VLMCALL.OBJ}
  356.  
  357. Procedure CallVlm (var Regs : IntRegisters; IntAddr : Pointer;
  358.                    DestID, DestFunc : Word); external;
  359.  
  360.  
  361. Procedure VlmCall (var Regs : IntRegisters; DestID, DestFunc : Word);
  362. begin
  363.    CallVlm(Regs,VlmAddr,DestID,DestFunc);
  364.    NovResult := Regs.AX;
  365. end;
  366.  
  367.  
  368. {VLM calls use server connection handles. This function returns the
  369.  connection handle of the default server.}
  370.  
  371. Function DefaultConnectionHandle : Word;
  372. var NovRegs : IntRegisters;
  373. begin
  374.    with NovRegs do begin
  375.       BX := 1;
  376.       VlmCall(NovRegs,$43,6);
  377.       DefaultConnectionHandle := CX;
  378.    end;
  379. end;
  380.  
  381.  
  382. {From Turbopower Software's OPINLINE.PAS program}
  383.  
  384. function PtrToLong(P : Pointer) : LongInt;
  385.   {-Convert pointer, in range $0:$0 to $FFFF:$000F, to LongInt}
  386. begin
  387.   PtrToLong := (LongInt(OS(P).S) shl 4)+OS(P).O;
  388. end;
  389.  
  390.  
  391. function LongToPtr(L : LongInt) : Pointer;
  392.   {-Return LongInt L as a normalized pointer}
  393. begin
  394.   LongToPtr := Ptr(Word(L shr 4), Word(L and $F));
  395. end;
  396.  
  397.  
  398. function AddLongToPtr(P : Pointer; L : LongInt) : Pointer;
  399.   {-Add a LongInt to a pointer, returning a normalized pointer}
  400. begin
  401.   AddLongToPtr := LongToPtr(L+PtrToLong(P));
  402. end;
  403.  
  404.  
  405. {When using NETX calls, the DS:SI registers point to the Request Buffer
  406.  and ES:DI points the the Reply Buffer. The first word of these buffers
  407.  is the buffer size.
  408.  
  409.  The VLM shells are different. The DS:SI registers point to a fragment list
  410.  containing up to 5 fragments for the data to be sent, and ES:DI points
  411.  to a fragment list of up to 5 fragments to receive data. Why Novell does
  412.  this escapes me. So I create a list with a single request and reply
  413.  fragment.
  414.  
  415.  These fragments no longer have the fragment length as the first word and
  416.  this makes it difficult to make a single interface that is smart enough
  417.  to make either a VLM call or a NetX call. What I do is build a Request
  418.  buffer with the first word for the length. If I then make a VLM call,
  419.  I move the pointer two bytes forward past the length word and copy the
  420.  length word into the fragment list. This way the old request and reply
  421.  buffers still work with the new VLM shells.}
  422.  
  423. var
  424.   ReqBuf : Pointer;
  425.   ReqBufSize : Word;
  426.   RepBuf : Pointer;
  427.   RepBufSize : Word;
  428.  
  429.  
  430. Procedure VLMTransportCall (Request, Reply : Pointer; Func : Word);
  431. var
  432.   NovRegs : IntRegisters;
  433.   P : Pointer;
  434. begin
  435.    ReqBuf := Request;
  436.    ReqBufSize := WordPtr(Request)^;
  437.    RepBuf := AddLongToPtr(Reply,2);
  438.    RepBufSize := WordPtr(Reply)^;
  439.    with NovRegs do begin
  440.       CX := DefaultConnectionHandle;
  441.       DS := Seg(ReqBuf);
  442.       SI := Ofs(ReqBuf);
  443.       ES := Seg(RepBuf);
  444.       DI := Ofs(RepBuf);
  445.       BX := 0;
  446.       DX := 0;
  447.       if ReqBufSize > 0 then BX := 1;
  448.       if RepBufSize > 0 then DX := 1;
  449.       AX := Func;
  450.    end;
  451.    VlmCall(NovRegs,$20,6);
  452. end;
  453.  
  454.  
  455. Procedure NetxTransportCall (Request, Reply : Pointer; Func : Byte);
  456. var Regs : Registers;
  457. begin
  458.    with Regs do begin
  459.       DS := Seg(Request^);
  460.       SI := Ofs(Request^);
  461.       ES := Seg(Reply^);
  462.       DI := Ofs(Reply^);
  463.       AH := Func;
  464.       MsDos(Regs);
  465.       NovResult := AL;
  466.    end;
  467. end;
  468.  
  469.  
  470. {All $E1 transport calls are mapped to VLM calls 21. Likewise, $E2 is
  471.  mapped to 22, and $E3 is mapped to 23. The difference in call numbers
  472.  is a value of $CC.}
  473.  
  474.  
  475. Procedure TransportCall (Request, Reply : Pointer; B : Byte);
  476. begin
  477.    if VlmLoaded then begin
  478.       VlmTransportCall(Request,Reply,B - $CC);
  479.    end else begin
  480.       NetxTransportCall(Request,Reply,B);
  481.    end;
  482. end;
  483.  
  484.  
  485. Procedure TransportCallE1 (Request, Reply : Pointer);
  486. begin
  487.    TransPortCall(Request,Reply,$E1);
  488. end;
  489.  
  490.  
  491. Procedure TransportCallE2 (Request, Reply : Pointer);
  492. begin
  493.    TransPortCall(Request,Reply,$E2);
  494. end;
  495.  
  496.  
  497. Procedure TransportCallE3 (Request, Reply : Pointer);
  498. begin
  499.    TransPortCall(Request,Reply,$E3);
  500. end;
  501.  
  502.  
  503. Function ConTableSize : Byte;
  504. {Returns the size of the connection table}
  505. var NovRegs : IntRegisters;
  506. begin
  507.    with NovRegs do begin
  508.       if VlmLoaded then begin
  509.          VlmCall(NovRegs,$10,$0F);
  510.          ConTableSize := DX;
  511.       end else ConTableSize := 8;
  512.    end;
  513. end;
  514.  
  515.  
  516. {The VLM shell allows up to 9 printers. (LPT1-LPT9)}
  517.  
  518. Function NumberOfPrinters : Byte;
  519. var NovRegs : IntRegisters;
  520. begin
  521.    if VlmLoaded then with NovRegs do begin
  522.       BX := 1;
  523.       VlmCall(NovRegs,$42,7);
  524.       if AL = 0 then NumberOfPrinters := BX else NumberOfPrinters := 3;
  525.    end else NumberOfPrinters := 3;
  526. end;
  527.  
  528.  
  529.  
  530. Function NovConnection : Word;
  531. {Returns the 16 bit connection number}
  532. var Regs : Registers;
  533.     NovRegs : IntRegisters;
  534. begin
  535.    if VlmLoaded then begin
  536.       with NovRegs do begin
  537.          CX := DefaultConnectionHandle;
  538.          BH := 13;
  539.          VlmCall(NovRegs,$10,7);
  540.          NovConnection := DX;
  541.       end;
  542.    end else begin
  543.       with Regs do begin
  544.          AH := $DC;
  545.          MsDos(Regs);
  546.          NovConnection := AL;
  547.       end;
  548.    end;
  549. end;
  550.  
  551.  
  552. Function NovBinderyAccess : Byte;
  553. var Request : record
  554.                  Len : Word;
  555.                  Fun : Byte;
  556.               end;
  557.     Reply : record
  558.                Len : Word;
  559.                Access : Byte;
  560.                Obj : LongInt;
  561.             end;
  562. begin
  563.    if NovConnection = 0 then begin
  564.       NovBinderyAccess := 0;
  565.       exit;
  566.    end;
  567.    Request.Len := SizeOf(Request);
  568.    Request.Fun := $46;
  569.    Reply.Len := SizeOf(Reply);
  570.    TransportCallE3(@Request,@Reply);
  571.    NovBinderyAccess := Reply.Access and 15;
  572. end;
  573.  
  574.  
  575. Procedure ReverseWord (var W : Word);
  576. var A : Array[1..2] of Byte absolute W;
  577.     B : Byte;
  578. begin
  579.    B := A[1];
  580.    A[1] := A[2];
  581.    A[2] := B;
  582. end;
  583.  
  584.  
  585. Procedure ReverseLongInt (var L : LongInt);
  586. var A : Array[1..4] of Byte absolute L;
  587.     B : Byte;
  588. begin
  589.    B := A[1];
  590.    A[1] := A[4];
  591.    A[4] := B;
  592.    B := A[2];
  593.    A[2] := A[3];
  594.    A[3] := B;
  595. end;
  596.  
  597.  
  598. Procedure FixString (var St : String);
  599. begin
  600.    St[0] := #255;
  601.    St[0] := char(pred(pos(#0,St)));
  602. end;
  603.  
  604.  
  605. Function LoginName (Conn : Word) : String;
  606. var Request : record
  607.                  Len : Word;
  608.                  Fun : Byte;
  609.           Connection : LongInt;
  610.               end;
  611.     Reply : record
  612.                Len : Word;
  613.                ID  : LongInt;
  614.                Typ : Word;
  615.               Name : Array[1..48] of byte;
  616.               Time : Array[1..10] of Byte;
  617.             end;
  618.     St : String;
  619. begin
  620.    Request.Len := SizeOf(Request);
  621.    if VlmLoaded then Request.Fun := $1C else Request.Fun := $16;
  622.    Request.Connection := Conn;
  623.    Reply.Len := SizeOf(Reply);
  624.    TransportCallE3(@Request,@Reply);
  625.    move(Reply.Name,St[1],48);
  626.    FixString(St);
  627.    LoginName := St;
  628. end;
  629.  
  630.  
  631. Function ObjectName (I : LongInt) : String;
  632. var Request : record
  633.                  Len : Word;
  634.                  Fun : Byte;
  635.                   ID : LongInt;
  636.               end;
  637.     Reply : record
  638.                Len : Word;
  639.                 ID : LongInt;
  640.                Typ : Word;
  641.               Name : Array[1..48] of Byte;
  642.             end;
  643.     St : String;
  644. begin
  645.    with Request do begin
  646.       Len := SizeOf(Request);
  647.       Fun := $36;
  648.       ID := I;
  649.    end;
  650.    Reply.Len := SizeOf(Reply);
  651.    TransportCallE3(@Request,@Reply);
  652.    move(Reply.Name,St[1],48);
  653.    FixString(St);
  654.    ObjectName := St;
  655. end;
  656.  
  657.  
  658. Function ObjectID (ObjName : Str80; T : Word) : LongInt;
  659. var Request : record
  660.                  Len : Word;
  661.                  Fun : Byte;
  662.                  Typ : Word;
  663.                 Name : String[48]
  664.               end;
  665.     Reply : record
  666.                Len : Word;
  667.                 ID : LongInt;
  668.                Typ : Word;
  669.               Name : Array[1..48] of Byte;
  670.             end;
  671. begin
  672.    ObjectID := 0;
  673.    with Request do begin
  674.       Len := SizeOf(Request);
  675.       Fun := $35;
  676.       Typ := T;
  677.       ReverseWord(Typ);
  678.       Name := ObjName;
  679.    end;
  680.    Reply.Len := SizeOf(Reply);
  681.    TransportCallE3(@Request,@Reply);
  682.    if NovResult = 0 then ObjectID := Reply.ID;
  683. end;
  684.  
  685.  
  686. Function ConsoleOperator : Boolean;
  687. var Request : record
  688.                  Len : Word;
  689.                  Fun : Byte;
  690.               end;
  691.     Reply : Word;
  692. begin
  693.    with Request do begin
  694.       Len := SizeOf(Request);
  695.       Fun := $C8;
  696.    end;
  697.    Reply := 0;
  698.    TransportCallE3(@Request,@Reply);
  699.    ConsoleOperator := NovResult = 0;
  700. end;
  701.  
  702.  
  703. Procedure InitVlm;
  704. var W : Array[1..2] of Word absolute VlmAddr;
  705.     Regs : Registers;
  706. begin
  707.    VlmAddr := nil;
  708.    with Regs do begin
  709.       AX := $7A20;
  710.       BX := 0;
  711.       Intr($2F,Regs);
  712.       if AX = 0 then begin
  713.          W[1] := BX;
  714.          W[2] := ES;
  715.       end;
  716.    end;
  717. end;
  718.  
  719.  
  720. begin
  721.    InitVlm;
  722. end.
  723.  
  724.  
  725. EVERYTHING HAS A PRICE
  726. ----------------------
  727.  
  728. This code can be distributed free with no charge or royalty under the
  729. following conditions:
  730.  
  731.  1) If you produce a commercial or shareware product you send us a free
  732.     copy of the programs for our own use and provide free upgrades upon
  733.     request.
  734.  
  735.  2) If you write a book using this information you send us each 2 free
  736.     copies of the book when published. You also have to credit us so
  737.     that we have a little something for our ego.
  738.  
  739.  
  740. You can reach Kim Kokkonen at:
  741.  
  742.      TurboPower Software
  743.      P.O. Box 49009
  744.      Colorado Springs, CO 80949-9009
  745.  
  746.      719-260-6641 (voice, Monday-Friday 9AM-5PM Mountian Time)
  747.      719-260-7151 (fax)
  748.      719-260-9726 (bbs)
  749.      Compuserve: 76004,2611 PCVENB Section 6
  750.  
  751.  
  752. You can reach Marc Perkel at:
  753.  
  754.      Computer Tyme
  755.      411 North Sherman, Suite 300
  756.      Springfield Mo. 65802
  757.  
  758.      417-866-1222 voice
  759.      417-866-1665 bbs/fax
  760.      Compuserve 71333,427 NVENA Section 3
  761.      MHS: Marc @ CTyme
  762.      Internet: Marc @ CTyme.MHS.Compuserve.com
  763.